from fastapi import FastAPI
from fastapi.responses import ORJSONResponse
from fastapi.staticfiles import StaticFiles

from tortoise.contrib.fastapi import register_tortoise
from tortoise.exceptions import (
    DBConnectionError as MysqlConnectionError,
    DoesNotExist as MysqlDoesNotExist,
    IntegrityError as MysqlIntegrityError,
    OperationalError as MysqlOperationalError,
    ValidationError as MysqlValidationError,
)

from fastapi.exceptions import HTTPException, RequestValidationError
from aioredis.exceptions import ConnectionError as RedisConnectionError
from exceptions import (
    http422_error_handler,
    http_error_handler,
    mysql_connection_error,
    mysql_does_not_exist,
    mysql_integrity_error,
    mysql_operational_error,
    mysql_validation_error,
    redis_connection_error,
    unicorn_exception_handler,
    UnicornException,
)
from starlette.middleware.cors import CORSMiddleware
from starlette.middleware.trustedhost import TrustedHostMiddleware
from starlette.middleware.sessions import SessionMiddleware
from middlewares import SetSessionMiddleware, ProcessTimeMiddleware
from config import settings

# from middlewares.log_req_resp import LogReqResMiddleware
from routers import custom_docs, api_routers
from config import settings

from loguru import logger

# 配置日志器
logger.configure(**settings.loguru_config)

app = FastAPI(
    debug=settings.debug,
    docs_url=None,
    redoc_url=None,
    swagger_ui_oauth2_redirect_url=settings.swagger_ui_oauth2_redirect_url,
    title=settings.project_title,
    description=settings.project_description,
    version=settings.project_version,
    default_response_class=ORJSONResponse,
)

# 自定义文档界面
custom_docs(app)

# 异常错误处理
app.add_exception_handler(HTTPException, http_error_handler)
app.add_exception_handler(RequestValidationError, http422_error_handler)
app.add_exception_handler(UnicornException, unicorn_exception_handler)
app.add_exception_handler(MysqlConnectionError, mysql_connection_error)
app.add_exception_handler(MysqlDoesNotExist, mysql_does_not_exist)
app.add_exception_handler(MysqlIntegrityError, mysql_integrity_error)
app.add_exception_handler(MysqlValidationError, mysql_validation_error)
app.add_exception_handler(MysqlOperationalError, mysql_operational_error)
app.add_exception_handler(RedisConnectionError, redis_connection_error)

# 中间件执行顺序：洋葱皮
#  请求阶段request 书写顺序的倒序执行由下往上执行 -> 路由函数执行 ->响应阶段response返回 中间件的书写正序执行由上往下执行
# 注册中间件，先注册的在内层, 洋葱模型
app.add_middleware(ProcessTimeMiddleware)
# app.add_middleware(LogReqResMiddleware)
app.add_middleware(SetSessionMiddleware)  # 设置session_cookie值random_str(),标识一个用户的会话
app.add_middleware(
    CORSMiddleware,
    allow_origins=settings.cors_origins,
    allow_credentials=settings.cors_allow_credentials,
    allow_methods=settings.cors_allow_methods,
    allow_headers=settings.cors_allow_headers,
)
# 提供了基于cookie的HTTP会话session_cookie管理功能。对请求中的session_cookie进行解密给后台函数，加密并在响应中返回给客户端。
# 同时，还提供了基于cookie的HTTP会话session_cookie的签名验证功能。
app.add_middleware(
    SessionMiddleware,
    secret_key=settings.session_secret_key,
    session_cookie=settings.session_cookie,
    max_age=settings.session_max_age,
)
app.add_middleware(TrustedHostMiddleware, allowed_hosts=settings.allowed_hosts)

# 挂载接口路由
app.include_router(api_routers)

# 静态资源目录
app.mount(settings.static_url_prefix, StaticFiles(directory=settings.static_dir), name="static")
# 用户上传目录
app.mount(settings.media_url_prefix, StaticFiles(directory=settings.media_dir), name="media")

# 注册数据库
register_tortoise(app, config=settings.tortoise_orm_config)


if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app="main:app", host="127.0.0.1", port=8000, reload=True)
